package com.david.cloud.filter;

import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * TODO 禁用ip过滤器是用sentinel
 * 全局ip过滤器
 * 添加全局过滤器器，进⾏行行IP注册接⼝口的防暴暴刷控制，超过阈值直接返回错误码及错误信息（错
 * 误码： 303，错误信息：您频繁进⾏行行注册，请求已被拒绝）
 */
//@Component
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class IpFilter implements GlobalFilter, ApplicationContextAware {
    public final Map<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<>();
    public ApplicationContext applicationContext;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 从request对象中获取客户端ip
        String clientIp = request.getRemoteAddress().getHostString();
        RateLimiter rateLimiter = rateLimiterMap.computeIfAbsent(clientIp, v -> {
            RateLimiter ratelimiter = applicationContext.getBean(RateLimiter.class);
            return ratelimiter;
        });
        boolean pass = rateLimiter.tryAcquire();
        if (!pass) {
            log.info("ip filtered--->{}", clientIp);
//            String data = "您频繁进⾏注册，请求已被拒绝!";
            String data = "您频繁进⾏访问，请求已被拒绝!";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            response.setStatusCode(HttpStatus.SEE_OTHER);
            return response.writeWith(Mono.just(wrap));
        } else {
            log.info("ip pass--->{}", clientIp);
            return chain.filter(exchange);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
